Skip to content

[TRTLLM-14511][feat] BREAKING: refactor per-request perf metrics for multi-process trtllm-server#16668

Open
reasonsolo wants to merge 10 commits into
NVIDIA:mainfrom
reasonsolo:feat/per_req_perf_metrics
Open

[TRTLLM-14511][feat] BREAKING: refactor per-request perf metrics for multi-process trtllm-server#16668
reasonsolo wants to merge 10 commits into
NVIDIA:mainfrom
reasonsolo:feat/per_req_perf_metrics

Conversation

@reasonsolo

@reasonsolo reasonsolo commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Doc: TRTLLM-Serving Performance Metrics Design

  • Replaces /perf_metrics polling with per-request metrics returned through response headers or an opt-in post-[DONE] SSE event.
  • Adds optional asynchronous JSONL dumping using the former /perf_metrics schema plus status and disagg_request_id.
  • Supports aggregated and disaggregated serving; ctx/gen metrics are combined by the serving fleet worker, never the coordinator.
  • Public metrics require both return_perf_metrics=true and X-TRTLLM-return-metrics: 1; file dumping is independently controlled by perf_metrics_output_dir.
  • Adds shared typed schemas, time-breakdown support, and agg/disagg E2E coverage.

Dev Engineer Review

  • Perf metrics exposure refactor (API-compatible intent): Removed /perf_metrics polling/endpoint behavior and moved per-request metrics delivery to:
    • Header-based delivery (gated by both return_perf_metrics=true and X-TRTLLM-return-metrics: 1).
    • Streaming delivery via SSE as an opt-in dedicated post-[DONE] metrics event (suppressed from user-visible streaming output).
    • Server-side JSONL output controlled independently via perf_metrics_output_dir.
  • Disaggregated propagation & gating correctness:
    • DisaggServerConfig added return_perf_metrics and perf_metrics_output_dir.
    • extract_disagg_cfg(...) now propagates options into context_servers and generation_servers and forces downstream returning when either return_perf_metrics is enabled or perf_metrics_output_dir is set.
    • Updated config inheritance iteration to avoid mutating/iterating over kwargs directly; switched to explicit keyword construction for DisaggServerConfig.
  • Typed, schema-driven metrics + disaggregation composition:
    • Added _perf_metrics_schema.py with TypedDict record types supporting aggregated + disaggregated phases and a unified PerfMetricsRecord union.
    • Centralized record building and disagg merging in tensorrt_llm/serve/perf_metrics.py (build_request_metrics_record, combine_disagg_metrics, header formatting, SSE event construction).
  • Server pipeline overhaul:
    • openai_server.py removed the legacy in-memory /perf_metrics implementation and deque/lock buffering; metrics are now built into per-request state and emitted at the correct time (explicitly awaited for both non-streaming and streaming completion).
    • openai_disagg_server.py replaced prior collector behavior with queue-latency-aware hooks + conditional collection/persistence, and removed the in-process /perf_metrics route registration.
    • Added PerfMetricsMiddleware and PerfMetricsJsonlWriter, with middleware opting-in header/SSE exposure based on X-TRTLLM-return-metrics: 1 and server config.
  • Client behavior changes:
    • OpenAIHttpClient now sets return-metrics headers when request_perf_metrics is enabled, extracts metrics from response headers and/or the SSE post-[DONE] metrics payload, and emits via hooks.
    • Streaming robustness improved: malformed metrics SSE payloads won’t break streaming; retry logic now re-emits disagg_request_id via hooks when regenerated.
    • Removed the old abstract/concrete collect_metrics() plumbing from OpenAIClient/OpenAIHttpClient.
  • Tooling & scripts alignment:
    • Benchmarks and time-breakdown tooling were updated to consume server-written JSONL from perf_metrics_output_dir instead of fetching /perf_metrics.
    • [DONE] handling in SSE consumption now exits immediately (return) to prevent extra-chunk processing.

CI failures noted in context: Four reported failures—prioritize validating the new gating/emission/JSONL expectations and any removed /perf_metrics behaviors:

  • PR_Github #60916, pipeline #49181, commit 5e0ac04
  • PR_Github #61165, pipeline #49414, commit d9ff361
  • PR_Github #61270, pipeline #49505, commit dbce2f7
  • PR_Github #61508, pipeline #49725, commit dbce2f7

Recommendation for follow-up investigation: focus on test failures around (1) header/SSE gating conditions, (2) disaggregated record merging and disagg_request_id propagation, and (3) JSONL writer output completeness/ordering (including time-breakdown fields), since the /perf_metrics endpoint and its client/scripting usage were removed.


QA Engineer Review

Test code/config changes detected (under tests/)

Integration / config updates

  • tests/integration/defs/accuracy/test_disaggregated_serving.py
    • Updated perf-metrics enablement to use perf_metrics_output_dir (temp-derived) instead of perf_metrics_max_requests.
    • Removed local /perf_metrics HTTP polling helper and invocation.
  • tests/integration/defs/disaggregated/test_disaggregated.py
    • Updated cluster/test harness to accept and inject perf_metrics_output_dir, validate via local JSONL artifacts, and remove prior /perf_metrics fetch/recording logic.
    • Updated perf-metrics assertions to use wait_for_perf_metrics_jsonl/JSONL readers rather than the HTTP endpoint.
  • tests/integration/defs/disaggregated/test_configs/disagg_config_conditional_deepseek_v3_v2.yaml
    • Set top-level return_perf_metrics: true.
  • tests/integration/defs/disaggregated/test_configs/disagg_config_metrics.yaml
    • Added top-level return_perf_metrics: true.

Test utilities

  • tests/test_common/perf_metrics_utils.py
    • Refactored to read perf_metrics-*.jsonl from an output directory.
    • Added read_perf_metrics_jsonl, wait_for_perf_metrics_jsonl.
    • Changed get_timing_metrics(...) to accept output_dir.

Unittest coverage

  • tests/unittest/disaggregated/test_disagg_utils.py
    • Added test_extract_disagg_metrics_controls.
  • tests/unittest/llmapi/apps/_test_openai_perf_metrics.py
    • Removed: test_metrics_endpoint
    • Added: test_return_perf_metrics_and_jsonl_dump
    • Added: test_streaming_metrics_require_request_opt_in
  • tests/unittest/llmapi/apps/_test_openai_chat_harmony_perf_metrics.py
    • Updated to validate via JSONL output (no /perf_metrics drain/count).
    • Signature updates to pass kv_cache_time_output_dir.
  • tests/unittest/llmapi/apps/test_disagg_serving_perf_metrics.py
    • Added fixture perf_metrics_output_dir
    • Added test: test_return_perf_metrics_and_jsonl_dump
    • Updated configuration plumbing to thread perf_metrics_output_dir.
  • tests/unittest/llmapi/apps/test_request_metrics.py
    • Added new test module covering header formatting, middleware behavior (headers/SSE), JSONL persistence, and record combination/parsing.
  • tests/unittest/others/test_time_breakdown.py
    • Added: test_parse_disaggregated_time_breakdown
    • Added: test_parse_jsonl_file
  • tests/unittest/disaggregated/test_disagg_openai_client.py
    • Added: test_internal_client_accepts_perf_metrics_header_size
    • Added: test_malformed_streaming_metrics_do_not_fail_request
  • Multi-node disaggregated serving tests
    • tests/unittest/llmapi/apps/_test_disagg_serving_multi_nodes.py: removed perf-metrics/timing-metrics plumbing.
    • tests/unittest/llmapi/apps/_test_disagg_serving_multi_nodes_service_discovery.py: removed perf-metrics/timing-metrics plumbing.
  • Removed test module
    • tests/unittest/llmapi/apps/test_disagg_perf_metrics_collector.py: entire module removed (collector serialization test deleted).

Coverage mapping vs test lists (CI/manual)

  • No updates to tests/integration/test_lists/ are confirmed from the available context (repo diff inspection returned no discoverable file changes in this environment).
  • Verdict: needs follow-up — coverage mapping to CBTS test lists wasn’t verifiable here, and the change is substantial (full migration off /perf_metrics to header/SSE/JSONL), so CI failures may require targeted test-list validation and/or additional waivers.

Description

Test Coverage

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

@reasonsolo
reasonsolo force-pushed the feat/per_req_perf_metrics branch 5 times, most recently from c0b42bf to 598991a Compare July 21, 2026 08:42
@reasonsolo reasonsolo changed the title Feat/per req perf metrics [TRTLLM-14511][feat] improve per-request perf metrics in multi-processed trtllm-server Jul 21, 2026
@reasonsolo reasonsolo added the api-compatible Accepted LLM API contract change that is backwards-compatible label Jul 21, 2026
@reasonsolo
reasonsolo force-pushed the feat/per_req_perf_metrics branch 7 times, most recently from 402269a to 5d92a7d Compare July 21, 2026 12:21
@reasonsolo
reasonsolo marked this pull request as ready for review July 22, 2026 05:19
@reasonsolo
reasonsolo requested review from a team as code owners July 22, 2026 05:19
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Replaces the HTTP /perf_metrics endpoint and in-memory request buffering with request-opt-in headers, streaming SSE metrics, and optional server-side JSONL output. Adds typed schemas, configuration propagation, client/server wiring, updated tooling, and validation.

Changes

Server-side JSONL performance metrics pipeline

Layer / File(s) Summary
Configuration and metrics contracts
tensorrt_llm/llmapi/disagg_utils.py, tensorrt_llm/llmapi/llm_args.py, tensorrt_llm/serve/_perf_metrics_schema.py, tensorrt_llm/serve/responses_utils.py
Adds metrics configuration, typed records, disaggregated propagation, request-ID hooks, and API metadata.
Metrics serialization and persistence
tensorrt_llm/serve/perf_metrics.py, tests/unittest/llmapi/apps/test_request_metrics.py
Builds, combines, serializes, persists, and exposes metrics through headers and SSE.
OpenAI client metrics propagation
tensorrt_llm/serve/openai_client.py, tests/unittest/disaggregated/test_disagg_openai_client.py
Adds request opt-in, response header/SSE parsing, hook delivery, and stream completion handling.
OpenAI and disaggregated server integration
tensorrt_llm/serve/openai_server.py, tensorrt_llm/serve/openai_disagg_server.py, tensorrt_llm/serve/openai_disagg_service.py, tests/unittest/disaggregated/test_openai_disagg_service.py
Gates collection, manages writers and middleware, combines disaggregated metrics, and completes context-only request hooks.
Benchmark and time-breakdown tooling
tensorrt_llm/serve/scripts/*, examples/disaggregated/slurm/benchmark/run_benchmark_aiperf.sh
Removes HTTP perf-metrics fetching and supports server-side JSONL input.
Integration and application validation
tests/integration/*, tests/unittest/llmapi/apps/*, tests/test_common/perf_metrics_utils.py
Configures JSONL output and validates metrics propagation, persistence, joining, headers, SSE, and timing parsing.

Estimated code review effort: 4 (Complex) | ~75 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OpenAIHttpClient
  participant OpenAIDisaggServer
  participant PerfMetricsMiddleware
  participant PerfMetricsJsonlWriter
  OpenAIHttpClient->>OpenAIDisaggServer: send metrics-enabled request
  OpenAIDisaggServer->>PerfMetricsMiddleware: collect completed request records
  PerfMetricsMiddleware->>OpenAIHttpClient: return headers or SSE metrics event
  PerfMetricsMiddleware->>PerfMetricsJsonlWriter: submit JSONL record
  PerfMetricsJsonlWriter->>PerfMetricsJsonlWriter: write per-process JSONL
Loading

Suggested reviewers: frankd412

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description has a useful summary, but the required Description, Test Coverage, and checklist sections are mostly left unfilled. Fill in the Description and Test Coverage sections, and complete the PR checklist with the relevant tests, labels, and documentation updates.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is specific, concise, and accurately summarizes the main breaking refactor of per-request perf metrics.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@reasonsolo
reasonsolo requested a review from pcastonguay July 23, 2026 02:50
@reasonsolo

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61165 [ run ] triggered by Bot. Commit: d9ff361 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61165 [ run ] completed with state FAILURE. Commit: d9ff361
/LLM/main/L0_MergeRequest_PR pipeline #49414 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
@reasonsolo
reasonsolo force-pushed the feat/per_req_perf_metrics branch from d9ff361 to 4f9117c Compare July 23, 2026 09:24
Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
@reasonsolo

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61270 [ run ] triggered by Bot. Commit: dbce2f7 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61270 [ run ] completed with state FAILURE. Commit: dbce2f7
/LLM/main/L0_MergeRequest_PR pipeline #49505 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@reasonsolo

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61508 [ run ] triggered by Bot. Commit: dbce2f7 Link to invocation

Comment thread tensorrt_llm/serve/openai_server.py Outdated
Comment thread tensorrt_llm/serve/perf_metrics.py Outdated
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61508 [ run ] completed with state FAILURE. Commit: dbce2f7
/LLM/main/L0_MergeRequest_PR pipeline #49725 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
@reasonsolo reasonsolo added api-breaking Accepted LLM API contract change that is backwards-incompatible and removed api-compatible Accepted LLM API contract change that is backwards-compatible labels Jul 24, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/unittest/llmapi/apps/test_request_metrics.py (1)

79-89: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Register the changed tests/unittest/llmapi/apps/test_request_metrics.py cases in the integration test lists, or explain why they’re excluded. No matching entries were found in tests/integration/test_lists/test-db/* or tests/integration/test_lists/qa/*, and there’s no CBTS touchmap/report to establish coverage. Changed tests: added test_time_breakdown_parser_accepts_header_derived_disagg_record, test_jsonl_writer_drops_only_malformed_record; modified test_metrics_headers_use_metric_list_syntax, test_combine_disagg_metrics_is_request_local, test_middleware_controls_public_headers, test_middleware_limits_non_streaming_metrics_headers, test_stream_metrics_follow_done, test_disconnect_after_done_is_ignored, test_file_middleware_intercepts_detail_headers. Coverage verdict: needs follow-up.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/llmapi/apps/test_request_metrics.py` around lines 79 - 89,
Register all listed changed tests from test_request_metrics.py in the
appropriate integration test lists under test-db or qa, or add a CBTS
touchmap/report documenting their exclusion and coverage rationale. Ensure every
added or modified test has an explicit coverage entry before completing the
change.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@tests/unittest/llmapi/apps/test_request_metrics.py`:
- Around line 79-89: Register all listed changed tests from
test_request_metrics.py in the appropriate integration test lists under test-db
or qa, or add a CBTS touchmap/report documenting their exclusion and coverage
rationale. Ensure every added or modified test has an explicit coverage entry
before completing the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6b147191-466e-4fe7-bb1e-092fcd6ed087

📥 Commits

Reviewing files that changed from the base of the PR and between dbce2f7 and f18b0f6.

📒 Files selected for processing (4)
  • tensorrt_llm/serve/openai_disagg_server.py
  • tensorrt_llm/serve/openai_server.py
  • tensorrt_llm/serve/perf_metrics.py
  • tests/unittest/llmapi/apps/test_request_metrics.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • tensorrt_llm/serve/openai_disagg_server.py
  • tensorrt_llm/serve/perf_metrics.py
  • tensorrt_llm/serve/openai_server.py

Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/unittest/disaggregated/test_openai_disagg_service.py`:
- Line 407: Replace assert_not_awaited() with assert_not_called() for
service._gen_client.send_request so the test verifies the method is never
invoked, not merely never awaited.
- Around line 385-407: Update test_context_only_response_finishes_hooks to use
assert_not_called() on service._gen_client.send_request instead of
assert_not_awaited(), ensuring any invocation of the generation client is
detected regardless of whether it was awaited.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 9eb4690b-6f6d-4620-8138-df3798cd5e5b

📥 Commits

Reviewing files that changed from the base of the PR and between f18b0f6 and cfee1bc.

📒 Files selected for processing (2)
  • tensorrt_llm/serve/openai_disagg_service.py
  • tests/unittest/disaggregated/test_openai_disagg_service.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tensorrt_llm/serve/openai_disagg_service.py

Comment on lines +385 to +407
@pytest.mark.asyncio
@pytest.mark.parametrize("stream", [False, True], ids=["non-streaming", "streaming"])
async def test_context_only_response_finishes_hooks(stream):
service = _make_service("context_first")
service._ctx_client = AsyncMock()
service._gen_client = AsyncMock()
service._coordinator.get_disagg_request_id = AsyncMock(return_value=42)
service._check_conditional_disagg = AsyncMock(return_value=(None, True))
service._check_gen_only_disagg = AsyncMock(return_value=False)
service._ctx_router.get_next_server = AsyncMock(return_value=("ctx:9000", {"server_info": {}}))
ctx_response = _make_completion_response("done", finish_reason="stop", context_only=True)
service._ctx_client.send_request = AsyncMock(return_value=ctx_response)
hooks = mock.Mock()
request = CompletionRequest(model="test-model", prompt="hello", stream=stream)

result = await service._send_disagg_request(request, hooks)
if stream:
assert [chunk async for chunk in result] == [b"data: [DONE]\n\n"]
else:
assert result is ctx_response

hooks.on_resp_done.assert_called_once_with("", request, ctx_response)
service._gen_client.send_request.assert_not_awaited()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
for dir in tests/integration/test_lists/test-db tests/integration/test_lists/qa; do
    if [ -d "$dir" ]; then
        echo "== $dir =="
        rg -n "test_context_only_response_finishes_hooks|test_openai_disagg_service" "$dir" || true
    else
        echo "Missing: $dir"
    fi
done

Repository: NVIDIA/TensorRT-LLM

Length of output: 346


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the test and the implementation path it exercises.
python3 - <<'PY'
from pathlib import Path

paths = [
    "tests/unittest/disaggregated/test_openai_disagg_service.py",
    "tensorrt_llm/serving/disaggregated/openai_service.py",
]
for p in paths:
    path = Path(p)
    print(f"\n== {p} ==")
    if not path.exists():
        print("missing")
        continue
    lines = path.read_text().splitlines()
    for i, line in enumerate(lines, 1):
        if "test_context_only_response_finishes_hooks" in line or "_send_disagg_request" in line or "send_request" in line:
            start = max(1, i - 20)
            end = min(len(lines), i + 40)
            print(f"-- context around line {i} --")
            for j in range(start, end + 1):
                print(f"{j:4d}: {lines[j-1]}")
PY

Repository: NVIDIA/TensorRT-LLM

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Probe unittest.mock.AsyncMock assertion semantics directly.
python3 - <<'PY'
from unittest.mock import AsyncMock

m = AsyncMock()
print("initial:", m.called, m.await_count)
try:
    m.assert_not_awaited()
    print("assert_not_awaited: pass before call")
except Exception as e:
    print("assert_not_awaited: fail before call", type(e).__name__, e)

_ = m("x")
print("after call:", m.called, m.await_count)
try:
    m.assert_not_awaited()
    print("assert_not_awaited: pass after call")
except Exception as e:
    print("assert_not_awaited: fail after call", type(e).__name__, e)

# create a fresh mock and await it
async def main():
    n = AsyncMock()
    await n("y")
    print("after await:", n.called, n.await_count)
    try:
        n.assert_not_awaited()
        print("assert_not_awaited: pass after await")
    except Exception as e:
        print("assert_not_awaited: fail after await", type(e).__name__, e)

import asyncio
asyncio.run(main())
PY

Repository: NVIDIA/TensorRT-LLM

Length of output: 482


Use assert_not_called() for the generation client
assert_not_awaited() still passes if send_request() is invoked but never awaited, so this test can miss an unwanted generation request.

Test coverage summary: test_context_only_response_finishes_hooks is added and listed in tests/integration/test_lists/test-db/l0_a10.yml; no matching qa/ entry. Coverage verdict: sufficient.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/disaggregated/test_openai_disagg_service.py` around lines 385
- 407, Update test_context_only_response_finishes_hooks to use
assert_not_called() on service._gen_client.send_request instead of
assert_not_awaited(), ensuring any invocation of the generation client is
detected regardless of whether it was awaited.

Source: Path instructions

assert result is ctx_response

hooks.on_resp_done.assert_called_once_with("", request, ctx_response)
service._gen_client.send_request.assert_not_awaited()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
from unittest.mock import AsyncMock

mock = AsyncMock()
pending = mock()
mock.assert_not_awaited()
assert mock.call_count == 1
pending.close()
print("assert_not_awaited does not imply assert_not_called")
PY

Repository: NVIDIA/TensorRT-LLM

Length of output: 209


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

path = Path("tests/unittest/disaggregated/test_openai_disagg_service.py")
lines = path.read_text().splitlines()
for start in (360, 390, 400, 410, 430):
    end = min(len(lines), start + 30)
    print(f"\n--- {path}:{start+1}-{end} ---")
    for i in range(start, end):
        print(f"{i+1:4d}: {lines[i]}")
PY

Repository: NVIDIA/TensorRT-LLM

Length of output: 8079


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

path = Path("tests/unittest/disaggregated/test_openai_disagg_service.py")
text = path.read_text().splitlines()

# Print the helper/implementation references around _send_disagg_request if present in same file.
for i, line in enumerate(text):
    if "async def _send_disagg_request" in line or "def _send_disagg_request" in line:
        start = max(0, i - 20)
        end = min(len(text), i + 220)
        print(f"--- {path}:{start+1}-{end} ---")
        for j in range(start, end):
            print(f"{j+1:4d}: {text[j]}")
        break
else:
    print("No _send_disagg_request implementation in this file")

PY

Repository: NVIDIA/TensorRT-LLM

Length of output: 209


Use assert_not_called() here

assert_not_awaited() still passes if service._gen_client.send_request is called but never awaited. This test should enforce the no-call contract.

Proposed fix
-    service._gen_client.send_request.assert_not_awaited()
+    service._gen_client.send_request.assert_not_called()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
service._gen_client.send_request.assert_not_awaited()
service._gen_client.send_request.assert_not_called()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/disaggregated/test_openai_disagg_service.py` at line 407,
Replace assert_not_awaited() with assert_not_called() for
service._gen_client.send_request so the test verifies the method is never
invoked, not merely never awaited.

@pcastonguay pcastonguay changed the title [TRTLLM-14511][feat] refactor per-request perf metrics for multi-process trtllm-server [TRTLLM-14511][feat] BREAKING: refactor per-request perf metrics for multi-process trtllm-server Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api-breaking Accepted LLM API contract change that is backwards-incompatible

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants